#ifndef __IM_HOTKEYS_H__
#define __IM_HOTKEYS_H__

#include <im_base_types.h>
#include <im_object.h>
#include <im_event.h>

/**
 * @defgroup IMHotkey IMHotkey and IMHotkeyProfile
 * @ingroup PublicIME
 * @{
 */

/** @struct IMHotkey
 *  @brief An object to associate a key code to one or more
 *         action events.
 */

/** @struct IMHotkeyProfile
 * @brief An object to hold a set of IMHotkey objects.
 *
 * An IMBUS component can register multiple IMHotkeyProfile
 * objects with either local or global scope into IMBUS,
 * which contains multiple set of hotkeys. Only one local
 * profile and one global profile can be set to active.
 *
 * When IMBUS receives a key event, it'll firstly check whether it
 * matches a hotkey in the current active local hotkey profile of
 * the IMEngine/IMLogic which is associated with the current focused
 * IC then all active global hotkey profiles of all components.
 * If a hotkey is matched, the associated events
 * will be performed and the key event will be swallowed by IMBUS.
 *
 * Two events are defined to set the active local/global hotkey profile
 * for specified component. So that a hotkey can be defined to switch
 * active hotkey profile on-the-fly.
 *
 * The active hotkey profile can also be switched by component by sending
 * hotkey profile switching events to IMBUS.
 */

IM_BEGIN_DECLS

#define IM_HOTKEY(p)                    (IM_TYPE_INSTANCE_CHECK_CAST((p),IM_TYPE_HOTKEY,IMHotkey))
#define IM_CONST_HOTKEY(p)              (IM_TYPE_INSTANCE_CHECK_CAST_CONST((p),IM_TYPE_HOTKEY,IMHotkey))
#define IM_HOTKEY_CLASS(c)              (IM_TYPE_CLASS_CHECK_CAST((c),IM_TYPE_HOTKEY,IMHotkeyClass))
#define IM_IS_HOTKEY(p)                 (IM_TYPE_INSTANCE_CHECK_TYPE((p),IM_TYPE_HOTKEY))
#define IM_IS_HOTKEY_CLASS(c)           (IM_TYPE_CLASS_CHECK_TYPE((c),IM_TYPE_HOTKEY))
#define IM_HOTKEY_GET_CLASS(p)          (IM_TYPE_INSTANCE_GET_CLASS_CAST((p),IM_TYPE_HOTKEY,IMHotkeyClass))

#define IM_HOTKEY_PROFILE(p)            (IM_TYPE_INSTANCE_CHECK_CAST((p),IM_TYPE_HOTKEY_PROFILE,IMHotkeyProfile))
#define IM_CONST_HOTKEY_PROFILE(p)      (IM_TYPE_INSTANCE_CHECK_CAST_CONST((p),IM_TYPE_HOTKEY_PROFILE,IMHotkeyProfile))
#define IM_HOTKEY_PROFILE_CLASS(c)      (IM_TYPE_CLASS_CHECK_CAST((c),IM_TYPE_HOTKEY_PROFILE,IMHotkeyProfileClass))
#define IM_IS_HOTKEY_PROFILE(p)         (IM_TYPE_INSTANCE_CHECK_TYPE((p),IM_TYPE_HOTKEY_PROFILE))
#define IM_IS_HOTKEY_PROFILE_CLASS(c)   (IM_TYPE_CLASS_CHECK_TYPE((c),IM_TYPE_HOTKEY_PROFILE))
#define IM_HOTKEY_PROFILE_GET_CLASS(p)  (IM_TYPE_INSTANCE_GET_CLASS_CAST((p),IM_TYPE_HOTKEY_PROFILE,IMHotkeyProfileClass))

typedef struct _IMHotkey                IMHotkey;
typedef struct _IMHotkeyClass           IMHotkeyClass;

typedef struct _IMHotkeyProfile         IMHotkeyProfile;
typedef struct _IMHotkeyProfileClass    IMHotkeyProfileClass;

/** @enum IMHotkeyProfileScope
 * @brief Indicate the effect scope of a hotkey profile.
 *
 * - IM_HOTKEY_PROFILE_LOCAL
 *   Indicates that the hotkey profile takes effect only when
 *   the current focused IC is active and associated to
 *   corresponding IMEngine/IMLogic.
 *   Only IMEngine/IMLogic can register local hotkey profile.
 * - IM_HOTKEY_PROFILE_GLOBAL
 *   Indicates that the hotkey profile takes effect all the time.
 *   Components other than IMEngines/IMLogics can only register
 *   global hotkey profiles.
 */
typedef enum
{
    IM_HOTKEY_PROFILE_LOCAL     = 0,
    IM_HOTKEY_PROFILE_GLOBAL    = 1,
} IMHotkeyProfileScope;

/**
 * @brief Create a new hotkey with specified key code
 *
 * Create a new object with the type of hotkey and set given keycode.
 *
 * @param keycode Keycode to be set as a hotkey
 *
 * @return Created IMHotkey object
 */
IMHotkey*           im_hotkey_new                   (IMUInt32            keycode);

/**
 * @brief Set key code of a hotkey
 *
 * Set keycode to a hotkey object.
 * Fail if the given keycode is invalid.
 *
 * @param hotkey    IMHotkey object to set keycode
 * @param keycode   Keycode to be set as a hotkey
 *
 * @return This function returns no value
 */
void                im_hotkey_set_key_code          (IMHotkey           *hotkey,
                                                     IMUInt32            keycode);
/**
 * @brief Get key code of a specified hotkey
 *
 * Get keycode of a IMHotkey object.
 * Fail if the given hotkey is invalid.
 *
 * @param hotkey IMHotkey object to get keycode
 *
 * @return keycode of the IMHotkey object. Return 0 if fail
 */
IMUInt32            im_hotkey_get_key_code          (const IMHotkey     *hotkey);

/**
 * @brief Get how many events stored in a hotkey.
 *
 * Get the size of the events array of given IMHotkey object.
 * Fail if the given hotkey is invalid.
 *
 * @param hotkey IMHotkey object to get the number of events
 *
 * @return Number of the events.
 *         Return 0 if the events array of the given hotkey object is NULL
 *         or operation is failed.
 */
IMSize              im_hotkey_get_n_events          (const IMHotkey     *hotkey);

/**
 * @brief Clear all events stored in a hotkey
 *
 * Destroy all the event objects in the events array of the given hotkey object.
 * Fail if the given hotkey is invalid.
 *
 * @param hotkey IMHotkey object which events will be clear
 *
 * @return This function returns no value
 */
void                im_hotkey_clear                 (IMHotkey           *hotkey);

/**
 * @brief Append an event to a specified IMHotkey object.
 *
 * Increase the reference count of the given event
 * and append the event to the events array of the given hotkey object.
 * If the events array is NULL, create a new array.
 * Fail if the given hotkey or event is invalid.
 *
 * @param hotkey    IMHotkey object
 * @param event     IMEvent to be appended to the IMHotkey object
 *
 * @return This function returns no value
 */
void                im_hotkey_append_event          (IMHotkey           *hotkey,
                                                     IMEvent            *event);
/**
 * @brief Get an event stored in a IMHotkey object at sepcified index.
 *
 * Get an IMEvent object at the given index of the
 * events array of the given hotkey object.
 * Return NULL if the given hotkey or the index is invalid.
 *
 * @param hotkey    IMHotkey object
 * @param index     Index which user want to get from the event array
 *
 * @ return IMEvent object if it exists at the given index, else return NULL
 */
IMEvent*            im_hotkey_get_event             (const IMHotkey     *hotkey,
                                                     IMSize              index);
/**
 * @brief Traverse all events stored in an hotkey object by calling
 *        specified function.
 *
 * Call the given function for each IMEvent object in the given IMHotkey object.
 *
 * @param hotkey    IMHotkey object
 * @param func      The iterator function
 * @param user_data Data to pass to the function
 *
 * @return This function returns no value
 */
void                im_hotkey_foreach_event         (const IMHotkey     *hotkey,
                                                     IMFunc              func,
                                                     IMPointer           user_data);

/**
 * @brief Create a new hotkey profile
 *
 * Create a new IMHotkeyProfile object and set a Uid and scope.
 *
 * @param id  Id of the profile to identify the profile among all
 *            profiles owned by a IMBUS component
 * @param scope Scope of the hotkey profile
 */
IMHotkeyProfile*    im_hotkey_profile_new           (IMUInt32                id,
                                                     IMHotkeyProfileScope    scope);
/**
 * @brief Set id of a specified hotkey profile
 *
 * Set id of the given IMHotkeyProfile object.
 * Existing id will be replaced with the new id.
 * Fail if the given hotkey profile is invalid.
 *
 * @param profile   Hotkey profile which id is set to
 * @param id        Unique id to be set to the hotkey profile
 *
 * @return This function returns no value
 */
void                im_hotkey_profile_set_id        (IMHotkeyProfile        *profile,
                                                     IMUInt32                id);
/**
 * @brief Get id of a specified hotkey profile
 *
 * Get id of the given IMHotkeyProfile object.
 * Return 0 if the given hotkey profile is invalid.
 *
 * @param profile Hotkey profile which user wants to get the id
 *
 * @return Uid of the hotkey profile
 */
IMUInt32            im_hotkey_profile_get_id        (const IMHotkeyProfile  *profile);
/**
 * @brief Set scope of a specified hotkey profile
 *
 * Set scope of the given IMHotkeyProfile object.
 * Existing scope will be replaced with the new scope.
 * Fail if the given hotkey profile is invalid.
 *
 * @param profile   Hotkey profile which user wants to set the scope to
 * @param scope     Scope of the hotkey profile
 *
 * @return This function returns no value
 */
void                im_hotkey_profile_set_scope     (IMHotkeyProfile        *profile,
                                                     IMHotkeyProfileScope    scope);
/**
 * @brief Get scope of a specified hotkey profile
 *
 * Get scope of the given IMHotkeyProfile object.
 * Fail if the given hotkey profile is invalid.
 *
 * @param profile Hotkey profile which user wants to get the scope from
 *
 * @return Scope of the hotkey profile, or retun NULL if the operation is failed.
 */
IMHotkeyProfileScope im_hotkey_profile_get_scope    (const IMHotkeyProfile  *profile);

/**
 * @brief Clear all hotkeys stored in a specified hotkey profile.
 *
 * Destroy the hotkeys hash table of the given IMHotkeyProfile object.
 * Fail if the given hotkey profile is invalid.
 *
 * @param profile Hotkey profile which user wants to clear
 *
 * @return This function returns no value
 */
void                im_hotkey_profile_clear         (IMHotkeyProfile        *profile);

/**
 * @brief Check whether a hotkey profile is empty or not
 *
 * If the given hotkey profile is invalid, return TRUE.
 * Check if hotkeys of the given profile is 0 or
 * the size of the hotkeys hash table is 0.
 *
 * @param profile Hotkey profile to be checked
 *
 * @return TRUE if the hotkey profile is empty, else return FALSE
 */
IMBool              im_hotkey_profile_empty         (const IMHotkeyProfile  *profile);
/**
 * @brief Add a hotkey into a specified hotkey profile.
 *
 * If a hotkey with the same key code is already available in the profile,
 * the old hotkey will be replaced by the new one.
 * Fail if the given profile or hotkey is invalid.
 *
 * @param profile   Hotkey profile which user wants to add a hotkey to
 * @param kotkey    Hotkey to be added
 *
 * @return This function returns no value
 */
void                im_hotkey_profile_add           (IMHotkeyProfile        *profile,
                                                     IMHotkey               *hotkey);
/**
 * @brief Remove a hotkey from a specified hotkey profile, by its key code.
 *
 * Lookup the given keycode in hotkeys hash table
 * and remove the hotkey if it is found in the table.
 * Fail if the given profile is invalid.
 *
 * @param profile Hotkey profile which user wants to remove a hotkey from
 * @param keycode Keycode of the hotkey to be removed
 *
 * @return This function returns no value
 */
void                im_hotkey_profile_remove        (IMHotkeyProfile        *profile,
                                                     IMUInt32                keycode);
/**
 * @brief Lookup a hotkey in a hotkey profile, by specified key code.
 *
 * If hotkeys hash table is not NULL and the hotkey with the given keycode,
 * returns the hotkey object.
 *
 * @param profile Hotkey profile
 * @param keycode Keycode of the hotkey to lookup
 *
 * @return The matched hotkey or NULL if no hotkey is matched.
 */
IMHotkey*           im_hotkey_profile_lookup        (const IMHotkeyProfile  *profile,
                                                     IMUInt32                keycode);
/**
 * @brief Traverse all hotkeys stored in a hotkey profile by calling
 * specified function.
 *
 * Call the given function for each IMHotkeyProfile object in the hotkeys hash table
 *
 * @param profile   Hotkey profile
 * @param func      The iterator function
 * @param user_data Data to pass to the function
 *
 * @return This function returns no value
 */
void                im_hotkey_profile_foreach       (const IMHotkeyProfile  *profile,
                                                     IMFunc                  func,
                                                     IMPointer               user_data);
IM_END_DECLS
/** @} */

#endif
/*
vi:ts=4:nowrap:ai:expandtab
*/
